#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
校准功能界面
Calibration Widget for NSA5312

功能特性：
- 多点温度校准
- 增益和零点校准
- 线性插值计算
- 校准数据管理
- LUT表生成
- 校准结果验证
"""

import json
import math
import numpy as np
from datetime import datetime
from typing import List, Dict, Tuple, Optional

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, 
                           QGridLayout, QLabel, QLineEdit, QPushButton, 
                           QTableWidget, QTableWidgetItem, QDoubleSpinBox,
                           QSpinBox, QComboBox, QTextEdit, QTabWidget,
                           QProgressBar, QMessageBox, QFileDialog, 
                           QCheckBox, QSplitter, QFrame)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QFont, QColor, QPalette

try:
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.figure import Figure
    MATPLOTLIB_AVAILABLE = True
except ImportError:
    MATPLOTLIB_AVAILABLE = False

from serial_handler import NSA5312CommandHelper, CommandResponse
from serial_protocol import NSA5312Protocol, NSA5312Calibration

class CalibrationPoint:
    """校准点数据"""
    
    def __init__(self, temperature: float = 25.0, raw_pressure: float = 0.0, 
                 target_pressure: float = 0.0, gain: float = 1.0, zero: float = 0.0):
        self.temperature = temperature
        self.raw_pressure = raw_pressure
        self.target_pressure = target_pressure
        self.gain = gain
        self.zero = zero
        self.timestamp = datetime.now()
    
    def to_dict(self) -> Dict:
        """转换为字典"""
        return {
            'temperature': self.temperature,
            'raw_pressure': self.raw_pressure,
            'target_pressure': self.target_pressure,
            'gain': self.gain,
            'zero': self.zero,
            'timestamp': self.timestamp.isoformat()
        }
    
    @classmethod
    def from_dict(cls, data: Dict) -> 'CalibrationPoint':
        """从字典创建"""
        point = cls(
            temperature=data['temperature'],
            raw_pressure=data['raw_pressure'],
            target_pressure=data['target_pressure'],
            gain=data['gain'],
            zero=data['zero']
        )
        if 'timestamp' in data:
            point.timestamp = datetime.fromisoformat(data['timestamp'])
        return point

class CalibrationWorker(QThread):
    """校准工作线程"""
    
    progress_updated = pyqtSignal(int)
    status_updated = pyqtSignal(str)
    calibration_completed = pyqtSignal(bool, str)
    point_measured = pyqtSignal(float, float, float)  # temperature, raw_value, target_value
    
    def __init__(self, command_helper: NSA5312CommandHelper, calibration_points: List[Tuple[float, float]]):
        super().__init__()
        self.command_helper = command_helper
        self.calibration_points = calibration_points  # [(temperature, target_pressure), ...]
        self.is_running = False
    
    def run(self):
        """执行校准过程"""
        self.is_running = True
        total_points = len(self.calibration_points)
        
        try:
            for i, (temperature, target_pressure) in enumerate(self.calibration_points):
                if not self.is_running:
                    break
                
                self.status_updated.emit(f"校准温度点 {temperature}°C...")
                
                # 等待温度稳定
                self.wait_for_temperature_stable(temperature)
                
                if not self.is_running:
                    break
                
                # 测量原始值
                raw_value = self.measure_raw_value()
                
                if raw_value is not None:
                    self.point_measured.emit(temperature, raw_value, target_pressure)
                    self.status_updated.emit(f"温度 {temperature}°C 校准完成")
                else:
                    self.status_updated.emit(f"温度 {temperature}°C 测量失败")
                
                # 更新进度
                progress = int((i + 1) / total_points * 100)
                self.progress_updated.emit(progress)
            
            if self.is_running:
                self.calibration_completed.emit(True, "校准完成")
            else:
                self.calibration_completed.emit(False, "校准被取消")
                
        except Exception as e:
            self.calibration_completed.emit(False, f"校准失败: {str(e)}")
    
    def wait_for_temperature_stable(self, target_temperature: float, tolerance: float = 1.0):
        """等待温度稳定"""
        stable_count = 0
        required_stable_count = 5
        
        while self.is_running and stable_count < required_stable_count:
            # 读取当前温度
            current_temp = self.read_temperature()
            
            if current_temp is not None:
                if abs(current_temp - target_temperature) <= tolerance:
                    stable_count += 1
                else:
                    stable_count = 0
                
                self.status_updated.emit(f"当前温度: {current_temp:.1f}°C, 目标: {target_temperature:.1f}°C")
            
            self.msleep(1000)  # 等待1秒
    
    def read_temperature(self) -> Optional[float]:
        """读取温度"""
        try:
            # 这里应该实现实际的温度读取
            # 示例：通过ADC读取温度传感器
            response = self.command_helper.read_adc_channel(63)  # 假设温度传感器在通道63
            
            if response.success and response.data:
                raw_value = int.from_bytes(response.data[:2], byteorder='big')
                # 转换为温度值（根据实际传感器特性）
                temperature = (raw_value * 0.077) + 51.6
                return temperature
            
        except Exception:
            pass
        
        return None
    
    def measure_raw_value(self) -> Optional[float]:
        """测量原始压力值"""
        try:
            # 多次测量取平均值
            measurements = []
            
            for _ in range(10):
                response = self.command_helper.read_adc_channel(0)  # 假设压力传感器在通道0
                
                if response.success and response.data:
                    raw_value = int.from_bytes(response.data[:2], byteorder='big')
                    measurements.append(raw_value)
                
                self.msleep(100)
            
            if measurements:
                return sum(measurements) / len(measurements)
            
        except Exception:
            pass
        
        return None
    
    def stop(self):
        """停止校准"""
        self.is_running = False

class CalibrationPlotWidget(QWidget):
    """校准曲线绘制控件"""
    
    def __init__(self):
        super().__init__()
        self.calibration_points = []
        self.init_ui()
    
    def init_ui(self):
        """初始化UI"""
        layout = QVBoxLayout()
        
        if MATPLOTLIB_AVAILABLE:
            # 创建图形
            self.figure = Figure(figsize=(10, 6))
            self.canvas = FigureCanvas(self.figure)
            layout.addWidget(self.canvas)
            
            # 创建子图
            self.ax1 = self.figure.add_subplot(221)
            self.ax1.set_title('增益校准曲线')
            self.ax1.set_xlabel('温度 (°C)')
            self.ax1.set_ylabel('增益系数')
            self.ax1.grid(True)
            
            self.ax2 = self.figure.add_subplot(222)
            self.ax2.set_title('零点校准曲线')
            self.ax2.set_xlabel('温度 (°C)')
            self.ax2.set_ylabel('零点偏移')
            self.ax2.grid(True)
            
            self.ax3 = self.figure.add_subplot(223)
            self.ax3.set_title('压力校准曲线')
            self.ax3.set_xlabel('原始值')
            self.ax3.set_ylabel('校准值')
            self.ax3.grid(True)
            
            self.ax4 = self.figure.add_subplot(224)
            self.ax4.set_title('误差分析')
            self.ax4.set_xlabel('温度 (°C)')
            self.ax4.set_ylabel('误差 (%)')
            self.ax4.grid(True)
            
            self.figure.tight_layout()
            
        else:
            # 如果没有matplotlib，显示文本信息
            self.info_text = QTextEdit()
            self.info_text.setReadOnly(True)
            self.info_text.setText("matplotlib未安装，无法显示图形。\n请安装matplotlib以显示校准曲线。")
            layout.addWidget(self.info_text)
        
        self.setLayout(layout)
    
    def update_plot(self, calibration_points: List[CalibrationPoint]):
        """更新图形"""
        if not MATPLOTLIB_AVAILABLE or not calibration_points:
            return
        
        self.calibration_points = calibration_points
        
        # 提取数据
        temperatures = [p.temperature for p in calibration_points]
        gains = [p.gain for p in calibration_points]
        zeros = [p.zero for p in calibration_points]
        raw_values = [p.raw_pressure for p in calibration_points]
        target_values = [p.target_pressure for p in calibration_points]
        
        # 清空图形
        self.ax1.clear()
        self.ax2.clear()
        self.ax3.clear()
        self.ax4.clear()
        
        # 绘制增益曲线
        self.ax1.plot(temperatures, gains, 'bo-', label='测量点')
        if len(temperatures) > 1:
            # 拟合曲线
            temp_fit = np.linspace(min(temperatures), max(temperatures), 100)
            gain_fit = np.interp(temp_fit, temperatures, gains)
            self.ax1.plot(temp_fit, gain_fit, 'r--', label='拟合曲线')
        self.ax1.set_title('增益校准曲线')
        self.ax1.set_xlabel('温度 (°C)')
        self.ax1.set_ylabel('增益系数')
        self.ax1.legend()
        self.ax1.grid(True)
        
        # 绘制零点曲线
        self.ax2.plot(temperatures, zeros, 'go-', label='测量点')
        if len(temperatures) > 1:
            zero_fit = np.interp(temp_fit, temperatures, zeros)
            self.ax2.plot(temp_fit, zero_fit, 'r--', label='拟合曲线')
        self.ax2.set_title('零点校准曲线')
        self.ax2.set_xlabel('温度 (°C)')
        self.ax2.set_ylabel('零点偏移')
        self.ax2.legend()
        self.ax2.grid(True)
        
        # 绘制压力校准曲线
        self.ax3.plot(raw_values, target_values, 'mo-', label='校准点')
        if len(raw_values) > 1:
            # 绘制理想直线
            min_raw, max_raw = min(raw_values), max(raw_values)
            min_target, max_target = min(target_values), max(target_values)
            self.ax3.plot([min_raw, max_raw], [min_target, max_target], 'r--', label='理想直线')
        self.ax3.set_title('压力校准曲线')
        self.ax3.set_xlabel('原始值')
        self.ax3.set_ylabel('校准值 (kPa)')
        self.ax3.legend()
        self.ax3.grid(True)
        
        # 绘制误差分析
        if len(calibration_points) > 1:
            errors = []
            for point in calibration_points:
                if point.target_pressure != 0:
                    error = abs(point.raw_pressure - point.target_pressure) / point.target_pressure * 100
                    errors.append(error)
                else:
                    errors.append(0)
            
            self.ax4.plot(temperatures, errors, 'ro-', label='校准误差')
            self.ax4.set_title('误差分析')
            self.ax4.set_xlabel('温度 (°C)')
            self.ax4.set_ylabel('误差 (%)')
            self.ax4.legend()
            self.ax4.grid(True)
        
        self.figure.tight_layout()
        self.canvas.draw()

class CalibrationWidget(QWidget):
    """校准功能主控件"""
    
    def __init__(self, command_helper: NSA5312CommandHelper):
        super().__init__()
        self.command_helper = command_helper
        self.calibration = NSA5312Calibration()
        self.calibration_points = []
        self.calibration_worker = None
        self.init_ui()
    
    def init_ui(self):
        """初始化UI"""
        layout = QVBoxLayout()
        
        # 创建选项卡
        tab_widget = QTabWidget()
        
        # 手动校准选项卡
        manual_tab = self.create_manual_calibration_tab()
        tab_widget.addTab(manual_tab, "手动校准")
        
        # 自动校准选项卡
        auto_tab = self.create_auto_calibration_tab()
        tab_widget.addTab(auto_tab, "自动校准")
        
        # 校准结果选项卡
        result_tab = self.create_result_tab()
        tab_widget.addTab(result_tab, "校准结果")
        
        # LUT表选项卡
        lut_tab = self.create_lut_tab()
        tab_widget.addTab(lut_tab, "LUT表管理")
        
        layout.addWidget(tab_widget)
        self.setLayout(layout)
    
    def create_manual_calibration_tab(self) -> QWidget:
        """创建手动校准选项卡"""
        widget = QWidget()
        layout = QVBoxLayout()
        
        # 校准点输入组
        input_group = QGroupBox("校准点输入")
        input_layout = QGridLayout()
        
        # 温度输入
        input_layout.addWidget(QLabel("温度 (°C):"), 0, 0)
        self.temp_spin = QDoubleSpinBox()
        self.temp_spin.setRange(-40, 125)
        self.temp_spin.setValue(25.0)
        self.temp_spin.setDecimals(1)
        input_layout.addWidget(self.temp_spin, 0, 1)
        
        # 原始压力值
        input_layout.addWidget(QLabel("原始值:"), 0, 2)
        self.raw_pressure_spin = QDoubleSpinBox()
        self.raw_pressure_spin.setRange(0, 65535)
        self.raw_pressure_spin.setDecimals(1)
        input_layout.addWidget(self.raw_pressure_spin, 0, 3)
        
        # 目标压力值
        input_layout.addWidget(QLabel("目标压力 (kPa):"), 1, 0)
        self.target_pressure_spin = QDoubleSpinBox()
        self.target_pressure_spin.setRange(-1000, 1000)
        self.target_pressure_spin.setDecimals(3)
        input_layout.addWidget(self.target_pressure_spin, 1, 1)
        
        # 测量按钮
        measure_btn = QPushButton("测量当前值")
        measure_btn.clicked.connect(self.measure_current_value)
        input_layout.addWidget(measure_btn, 1, 2)
        
        # 添加校准点按钮
        add_point_btn = QPushButton("添加校准点")
        add_point_btn.clicked.connect(self.add_calibration_point)
        input_layout.addWidget(add_point_btn, 1, 3)
        
        input_group.setLayout(input_layout)
        layout.addWidget(input_group)
        
        # 校准点表格
        table_group = QGroupBox("校准点列表")
        table_layout = QVBoxLayout()
        
        self.calibration_table = QTableWidget()
        self.calibration_table.setColumnCount(6)
        self.calibration_table.setHorizontalHeaderLabels([
            "温度 (°C)", "原始值", "目标值 (kPa)", "增益", "零点", "时间"
        ])
        table_layout.addWidget(self.calibration_table)
        
        # 表格控制按钮
        table_button_layout = QHBoxLayout()
        
        delete_point_btn = QPushButton("删除选中点")
        delete_point_btn.clicked.connect(self.delete_selected_point)
        table_button_layout.addWidget(delete_point_btn)
        
        clear_points_btn = QPushButton("清空所有点")
        clear_points_btn.clicked.connect(self.clear_all_points)
        table_button_layout.addWidget(clear_points_btn)
        
        calculate_btn = QPushButton("计算校准系数")
        calculate_btn.clicked.connect(self.calculate_calibration)
        table_button_layout.addWidget(calculate_btn)
        
        table_button_layout.addStretch()
        table_layout.addLayout(table_button_layout)
        
        table_group.setLayout(table_layout)
        layout.addWidget(table_group)
        
        widget.setLayout(layout)
        return widget
    
    def create_auto_calibration_tab(self) -> QWidget:
        """创建自动校准选项卡"""
        widget = QWidget()
        layout = QVBoxLayout()
        
        # 自动校准配置组
        config_group = QGroupBox("自动校准配置")
        config_layout = QGridLayout()
        
        # 温度点配置
        config_layout.addWidget(QLabel("起始温度 (°C):"), 0, 0)
        self.auto_start_temp = QDoubleSpinBox()
        self.auto_start_temp.setRange(-40, 125)
        self.auto_start_temp.setValue(-20)
        config_layout.addWidget(self.auto_start_temp, 0, 1)
        
        config_layout.addWidget(QLabel("结束温度 (°C):"), 0, 2)
        self.auto_end_temp = QDoubleSpinBox()
        self.auto_end_temp.setRange(-40, 125)
        self.auto_end_temp.setValue(80)
        config_layout.addWidget(self.auto_end_temp, 0, 3)
        
        config_layout.addWidget(QLabel("温度步长 (°C):"), 1, 0)
        self.auto_temp_step = QDoubleSpinBox()
        self.auto_temp_step.setRange(1, 50)
        self.auto_temp_step.setValue(20)
        config_layout.addWidget(self.auto_temp_step, 1, 1)
        
        # 压力点配置
        config_layout.addWidget(QLabel("压力点 (kPa):"), 1, 2)
        self.auto_pressure_edit = QLineEdit()
        self.auto_pressure_edit.setText("0, 50, 100")
        self.auto_pressure_edit.setPlaceholderText("用逗号分隔多个压力点")
        config_layout.addWidget(self.auto_pressure_edit, 1, 3)
        
        config_group.setLayout(config_layout)
        layout.addWidget(config_group)
        
        # 校准控制组
        control_group = QGroupBox("校准控制")
        control_layout = QHBoxLayout()
        
        self.start_auto_btn = QPushButton("开始自动校准")
        self.start_auto_btn.clicked.connect(self.start_auto_calibration)
        control_layout.addWidget(self.start_auto_btn)
        
        self.stop_auto_btn = QPushButton("停止校准")
        self.stop_auto_btn.clicked.connect(self.stop_auto_calibration)
        self.stop_auto_btn.setEnabled(False)
        control_layout.addWidget(self.stop_auto_btn)
        
        control_layout.addStretch()
        control_group.setLayout(control_layout)
        layout.addWidget(control_group)
        
        # 进度显示组
        progress_group = QGroupBox("校准进度")
        progress_layout = QVBoxLayout()
        
        self.calibration_progress = QProgressBar()
        progress_layout.addWidget(self.calibration_progress)
        
        self.calibration_status = QLabel("等待开始校准")
        progress_layout.addWidget(self.calibration_status)
        
        progress_group.setLayout(progress_layout)
        layout.addWidget(progress_group)
        
        layout.addStretch()
        widget.setLayout(layout)
        return widget
    
    def create_result_tab(self) -> QWidget:
        """创建校准结果选项卡"""
        widget = QWidget()
        layout = QVBoxLayout()
        
        # 创建分割器
        splitter = QSplitter(Qt.Vertical)
        
        # 校准曲线图
        self.plot_widget = CalibrationPlotWidget()
        splitter.addWidget(self.plot_widget)
        
        # 结果信息
        result_group = QGroupBox("校准结果")
        result_layout = QVBoxLayout()
        
        self.result_text = QTextEdit()
        self.result_text.setMaximumHeight(150)
        self.result_text.setReadOnly(True)
        result_layout.addWidget(self.result_text)
        
        # 结果控制按钮
        result_button_layout = QHBoxLayout()
        
        update_plot_btn = QPushButton("更新图形")
        update_plot_btn.clicked.connect(self.update_calibration_plot)
        result_button_layout.addWidget(update_plot_btn)
        
        export_result_btn = QPushButton("导出结果")
        export_result_btn.clicked.connect(self.export_calibration_result)
        result_button_layout.addWidget(export_result_btn)
        
        result_button_layout.addStretch()
        result_layout.addLayout(result_button_layout)
        
        result_group.setLayout(result_layout)
        splitter.addWidget(result_group)
        
        layout.addWidget(splitter)
        widget.setLayout(layout)
        return widget
    
    def create_lut_tab(self) -> QWidget:
        """创建LUT表选项卡"""
        widget = QWidget()
        layout = QVBoxLayout()
        
        # LUT配置组
        lut_config_group = QGroupBox("LUT表配置")
        lut_config_layout = QGridLayout()
        
        # 温度范围
        lut_config_layout.addWidget(QLabel("温度范围:"), 0, 0)
        self.lut_temp_min = QDoubleSpinBox()
        self.lut_temp_min.setRange(-40, 125)
        self.lut_temp_min.setValue(-20)
        lut_config_layout.addWidget(self.lut_temp_min, 0, 1)
        
        lut_config_layout.addWidget(QLabel("到"), 0, 2)
        self.lut_temp_max = QDoubleSpinBox()
        self.lut_temp_max.setRange(-40, 125)
        self.lut_temp_max.setValue(80)
        lut_config_layout.addWidget(self.lut_temp_max, 0, 3)
        
        # LUT点数
        lut_config_layout.addWidget(QLabel("LUT点数:"), 1, 0)
        self.lut_points_spin = QSpinBox()
        self.lut_points_spin.setRange(2, 14)
        self.lut_points_spin.setValue(8)
        lut_config_layout.addWidget(self.lut_points_spin, 1, 1)
        
        # 生成LUT按钮
        generate_lut_btn = QPushButton("生成LUT表")
        generate_lut_btn.clicked.connect(self.generate_lut_table)
        lut_config_layout.addWidget(generate_lut_btn, 1, 2, 1, 2)
        
        lut_config_group.setLayout(lut_config_layout)
        layout.addWidget(lut_config_group)
        
        # LUT表显示
        lut_table_group = QGroupBox("LUT表数据")
        lut_table_layout = QVBoxLayout()
        
        self.lut_table = QTableWidget()
        self.lut_table.setColumnCount(4)
        self.lut_table.setHorizontalHeaderLabels([
            "Bank", "温度 (°C)", "增益DAC", "零点DAC"
        ])
        lut_table_layout.addWidget(self.lut_table)
        
        # LUT控制按钮
        lut_button_layout = QHBoxLayout()
        
        save_lut_btn = QPushButton("保存LUT")
        save_lut_btn.clicked.connect(self.save_lut_table)
        lut_button_layout.addWidget(save_lut_btn)
        
        load_lut_btn = QPushButton("加载LUT")
        load_lut_btn.clicked.connect(self.load_lut_table)
        lut_button_layout.addWidget(load_lut_btn)
        
        download_lut_btn = QPushButton("下载到设备")
        download_lut_btn.clicked.connect(self.download_lut_to_device)
        lut_button_layout.addWidget(download_lut_btn)
        
        lut_button_layout.addStretch()
        lut_table_layout.addLayout(lut_button_layout)
        
        lut_table_group.setLayout(lut_table_layout)
        layout.addWidget(lut_table_group)
        
        widget.setLayout(layout)
        return widget
    
    def measure_current_value(self):
        """测量当前值"""
        try:
            # 测量当前ADC值
            response = self.command_helper.read_adc_channel(0)
            
            if response.success and response.data:
                raw_value = int.from_bytes(response.data[:2], byteorder='big')
                self.raw_pressure_spin.setValue(raw_value)
                
                # 同时测量温度
                temp_response = self.command_helper.read_adc_channel(63)
                if temp_response.success and temp_response.data:
                    temp_raw = int.from_bytes(temp_response.data[:2], byteorder='big')
                    if temp_raw & 0x8000:
                        temp_raw = temp_raw - 65536
                    temperature = (temp_raw * 0.077) + 51.6
                    self.temp_spin.setValue(temperature)
                
                QMessageBox.information(self, "测量完成", f"原始值: {raw_value}\n温度: {temperature:.1f}°C")
            else:
                QMessageBox.warning(self, "错误", f"测量失败: {response.error_msg}")
                
        except Exception as e:
            QMessageBox.critical(self, "错误", f"测量异常: {str(e)}")
    
    def add_calibration_point(self):
        """添加校准点"""
        temperature = self.temp_spin.value()
        raw_pressure = self.raw_pressure_spin.value()
        target_pressure = self.target_pressure_spin.value()
        
        # 创建校准点
        point = CalibrationPoint(
            temperature=temperature,
            raw_pressure=raw_pressure,
            target_pressure=target_pressure
        )
        
        self.calibration_points.append(point)
        self.update_calibration_table()
        
        # 自动递增温度值
        self.temp_spin.setValue(temperature + 10)
    
    def delete_selected_point(self):
        """删除选中的校准点"""
        current_row = self.calibration_table.currentRow()
        if 0 <= current_row < len(self.calibration_points):
            del self.calibration_points[current_row]
            self.update_calibration_table()
    
    def clear_all_points(self):
        """清空所有校准点"""
        reply = QMessageBox.question(
            self, "确认", "确定要清空所有校准点吗？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.calibration_points.clear()
            self.update_calibration_table()
    
    def update_calibration_table(self):
        """更新校准点表格"""
        self.calibration_table.setRowCount(len(self.calibration_points))
        
        for row, point in enumerate(self.calibration_points):
            self.calibration_table.setItem(row, 0, QTableWidgetItem(f"{point.temperature:.1f}"))
            self.calibration_table.setItem(row, 1, QTableWidgetItem(f"{point.raw_pressure:.1f}"))
            self.calibration_table.setItem(row, 2, QTableWidgetItem(f"{point.target_pressure:.3f}"))
            self.calibration_table.setItem(row, 3, QTableWidgetItem(f"{point.gain:.6f}"))
            self.calibration_table.setItem(row, 4, QTableWidgetItem(f"{point.zero:.6f}"))
            self.calibration_table.setItem(row, 5, QTableWidgetItem(point.timestamp.strftime("%H:%M:%S")))
    
    def calculate_calibration(self):
        """计算校准系数"""
        if len(self.calibration_points) < 2:
            QMessageBox.warning(self, "错误", "至少需要2个校准点")
            return
        
        try:
            # 计算增益和零点校准系数
            for point in self.calibration_points:
                if point.raw_pressure != 0:
                    point.gain = point.target_pressure / point.raw_pressure
                else:
                    point.gain = 1.0
                
                point.zero = point.target_pressure - (point.raw_pressure * point.gain)
            
            # 更新表格
            self.update_calibration_table()
            
            # 更新校准对象
            self.calibration.temperature_points = [p.temperature for p in self.calibration_points]
            self.calibration.gain_coefficients = [p.gain for p in self.calibration_points]
            self.calibration.zero_coefficients = [p.zero for p in self.calibration_points]
            
            # 更新结果显示
            self.update_result_display()
            
            QMessageBox.information(self, "成功", "校准系数计算完成")
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"计算校准系数失败: {str(e)}")
    
    def update_result_display(self):
        """更新结果显示"""
        if not self.calibration_points:
            self.result_text.clear()
            return
        
        result_text = "校准结果统计:\n\n"
        
        # 温度范围
        temperatures = [p.temperature for p in self.calibration_points]
        result_text += f"温度范围: {min(temperatures):.1f}°C ~ {max(temperatures):.1f}°C\n"
        
        # 增益范围
        gains = [p.gain for p in self.calibration_points]
        result_text += f"增益范围: {min(gains):.6f} ~ {max(gains):.6f}\n"
        
        # 零点范围
        zeros = [p.zero for p in self.calibration_points]
        result_text += f"零点范围: {min(zeros):.6f} ~ {max(zeros):.6f}\n"
        
        # 精度分析
        errors = []
        for point in self.calibration_points:
            if point.target_pressure != 0:
                calibrated_value = point.raw_pressure * point.gain + point.zero
                error = abs(calibrated_value - point.target_pressure) / point.target_pressure * 100
                errors.append(error)
        
        if errors:
            result_text += f"\n精度分析:\n"
            result_text += f"最大误差: {max(errors):.3f}%\n"
            result_text += f"平均误差: {sum(errors)/len(errors):.3f}%\n"
            result_text += f"误差标准差: {np.std(errors):.3f}%\n"
        
        self.result_text.setText(result_text)
    
    def update_calibration_plot(self):
        """更新校准图形"""
        self.plot_widget.update_plot(self.calibration_points)
    
    def start_auto_calibration(self):
        """开始自动校准"""
        try:
            # 解析配置
            start_temp = self.auto_start_temp.value()
            end_temp = self.auto_end_temp.value()
            temp_step = self.auto_temp_step.value()
            
            pressure_str = self.auto_pressure_edit.text()
            pressure_points = [float(p.strip()) for p in pressure_str.split(',')]
            
            # 生成校准点列表
            calibration_points = []
            temp = start_temp
            while temp <= end_temp:
                for pressure in pressure_points:
                    calibration_points.append((temp, pressure))
                temp += temp_step
            
            if not calibration_points:
                QMessageBox.warning(self, "错误", "没有有效的校准点")
                return
            
            # 创建并启动工作线程
            self.calibration_worker = CalibrationWorker(self.command_helper, calibration_points)
            self.calibration_worker.progress_updated.connect(self.calibration_progress.setValue)
            self.calibration_worker.status_updated.connect(self.calibration_status.setText)
            self.calibration_worker.calibration_completed.connect(self.on_auto_calibration_completed)
            self.calibration_worker.point_measured.connect(self.on_point_measured)
            
            self.calibration_worker.start()
            
            # 更新UI状态
            self.start_auto_btn.setEnabled(False)
            self.stop_auto_btn.setEnabled(True)
            self.calibration_progress.setValue(0)
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"启动自动校准失败: {str(e)}")
    
    def stop_auto_calibration(self):
        """停止自动校准"""
        if self.calibration_worker:
            self.calibration_worker.stop()
            self.calibration_worker.wait()
            self.calibration_worker = None
        
        self.start_auto_btn.setEnabled(True)
        self.stop_auto_btn.setEnabled(False)
        self.calibration_status.setText("校准已停止")
    
    def on_auto_calibration_completed(self, success: bool, message: str):
        """自动校准完成回调"""
        self.start_auto_btn.setEnabled(True)
        self.stop_auto_btn.setEnabled(False)
        
        if success:
            QMessageBox.information(self, "成功", message)
            # 计算校准系数
            self.calculate_calibration()
        else:
            QMessageBox.warning(self, "失败", message)
    
    def on_point_measured(self, temperature: float, raw_value: float, target_value: float):
        """测量点完成回调"""
        point = CalibrationPoint(
            temperature=temperature,
            raw_pressure=raw_value,
            target_pressure=target_value
        )
        
        self.calibration_points.append(point)
        self.update_calibration_table()
    
    def generate_lut_table(self):
        """生成LUT表"""
        if not self.calibration_points:
            QMessageBox.warning(self, "错误", "请先完成校准")
            return
        
        try:
            temp_min = self.lut_temp_min.value()
            temp_max = self.lut_temp_max.value()
            num_points = self.lut_points_spin.value()
            
            # 生成温度点
            temp_step = (temp_max - temp_min) / (num_points - 1)
            lut_temps = [temp_min + i * temp_step for i in range(num_points)]
            
            # 更新LUT表格
            self.lut_table.setRowCount(num_points)
            
            for i, temp in enumerate(lut_temps):
                # 线性插值计算增益和零点
                gain, zero = self.calibration.calculate_linear_interpolation(temp)
                
                # 转换为DAC值
                gain_dac = self.calibration.calculate_dac_value(gain, True)
                zero_dac = self.calibration.calculate_dac_value(zero, False)
                
                # 填充表格
                self.lut_table.setItem(i, 0, QTableWidgetItem(str(i)))
                self.lut_table.setItem(i, 1, QTableWidgetItem(f"{temp:.1f}"))
                self.lut_table.setItem(i, 2, QTableWidgetItem(f"0x{gain_dac:04X}"))
                self.lut_table.setItem(i, 3, QTableWidgetItem(f"0x{zero_dac:04X}"))
            
            QMessageBox.information(self, "成功", f"LUT表生成完成，共{num_points}个点")
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"生成LUT表失败: {str(e)}")
    
    def save_lut_table(self):
        """保存LUT表"""
        filename, _ = QFileDialog.getSaveFileName(
            self, "保存LUT表", "", "JSON Files (*.json);;All Files (*)"
        )
        
        if filename:
            try:
                lut_data = {
                    'calibration_points': [p.to_dict() for p in self.calibration_points],
                    'lut_table': [],
                    'generation_time': datetime.now().isoformat()
                }
                
                # 导出LUT表数据
                for row in range(self.lut_table.rowCount()):
                    bank = self.lut_table.item(row, 0).text()
                    temp = self.lut_table.item(row, 1).text()
                    gain_dac = self.lut_table.item(row, 2).text()
                    zero_dac = self.lut_table.item(row, 3).text()
                    
                    lut_data['lut_table'].append({
                        'bank': int(bank),
                        'temperature': float(temp),
                        'gain_dac': gain_dac,
                        'zero_dac': zero_dac
                    })
                
                with open(filename, 'w', encoding='utf-8') as f:
                    json.dump(lut_data, f, indent=2, ensure_ascii=False)
                
                QMessageBox.information(self, "成功", f"LUT表已保存到: {filename}")
                
            except Exception as e:
                QMessageBox.critical(self, "错误", f"保存LUT表失败: {str(e)}")
    
    def load_lut_table(self):
        """加载LUT表"""
        filename, _ = QFileDialog.getOpenFileName(
            self, "加载LUT表", "", "JSON Files (*.json);;All Files (*)"
        )
        
        if filename:
            try:
                with open(filename, 'r', encoding='utf-8') as f:
                    lut_data = json.load(f)
                
                # 恢复校准点
                if 'calibration_points' in lut_data:
                    self.calibration_points = [
                        CalibrationPoint.from_dict(p) for p in lut_data['calibration_points']
                    ]
                    self.update_calibration_table()
                
                # 恢复LUT表
                if 'lut_table' in lut_data:
                    lut_table = lut_data['lut_table']
                    self.lut_table.setRowCount(len(lut_table))
                    
                    for row, entry in enumerate(lut_table):
                        self.lut_table.setItem(row, 0, QTableWidgetItem(str(entry['bank'])))
                        self.lut_table.setItem(row, 1, QTableWidgetItem(f"{entry['temperature']:.1f}"))
                        self.lut_table.setItem(row, 2, QTableWidgetItem(entry['gain_dac']))
                        self.lut_table.setItem(row, 3, QTableWidgetItem(entry['zero_dac']))
                
                QMessageBox.information(self, "成功", f"LUT表已从 {filename} 加载")
                
            except Exception as e:
                QMessageBox.critical(self, "错误", f"加载LUT表失败: {str(e)}")
    
    def download_lut_to_device(self):
        """下载LUT表到设备"""
        if self.lut_table.rowCount() == 0:
            QMessageBox.warning(self, "错误", "请先生成LUT表")
            return
        
        try:
            # 这里应该实现实际的LUT下载功能
            # 由于NSA5312的OWI编程比较复杂，这里只是示例
            
            QMessageBox.information(self, "提示", 
                "LUT表下载功能需要专用的OWI编程器。\n"
                "请使用生成的LUT数据配合官方编程工具进行烧写。")
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"下载LUT表失败: {str(e)}")
    
    def export_calibration_result(self):
        """导出校准结果"""
        filename, _ = QFileDialog.getSaveFileName(
            self, "导出校准结果", "", 
            "JSON Files (*.json);;CSV Files (*.csv);;All Files (*)"
        )
        
        if filename:
            try:
                if filename.endswith('.json'):
                    self.export_to_json(filename)
                elif filename.endswith('.csv'):
                    self.export_to_csv(filename)
                else:
                    self.export_to_json(filename + '.json')
                
                QMessageBox.information(self, "成功", f"校准结果已导出到: {filename}")
                
            except Exception as e:
                QMessageBox.critical(self, "错误", f"导出校准结果失败: {str(e)}")
    
    def export_to_json(self, filename: str):
        """导出为JSON格式"""
        data = {
            'calibration_info': {
                'total_points': len(self.calibration_points),
                'temperature_range': {
                    'min': min(p.temperature for p in self.calibration_points) if self.calibration_points else 0,
                    'max': max(p.temperature for p in self.calibration_points) if self.calibration_points else 0
                },
                'export_time': datetime.now().isoformat()
            },
            'calibration_points': [p.to_dict() for p in self.calibration_points],
            'calibration_coefficients': self.calibration.export_calibration_data()
        }
        
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
    
    def export_to_csv(self, filename: str):
        """导出为CSV格式"""
        import csv
        
        with open(filename, 'w', newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            
            # 写入表头
            writer.writerow([
                '温度(°C)', '原始值', '目标值(kPa)', '增益', '零点', '校准时间'
            ])
            
            # 写入数据
            for point in self.calibration_points:
                writer.writerow([
                    point.temperature,
                    point.raw_pressure,
                    point.target_pressure,
                    point.gain,
                    point.zero,
                    point.timestamp.isoformat()
                ])
    
    def export_config(self) -> Dict:
        """导出配置"""
        return {
            'calibration_points': [p.to_dict() for p in self.calibration_points],
            'calibration_data': self.calibration.export_calibration_data()
        }
    
    def import_config(self, config: Dict):
        """导入配置"""
        if 'calibration_points' in config:
            self.calibration_points = [
                CalibrationPoint.from_dict(p) for p in config['calibration_points']
            ]
            self.update_calibration_table()
        
        if 'calibration_data' in config:
            self.calibration.import_calibration_data(config['calibration_data'])